#include "threads.h"
#include "data.h"
#include "protos.h"

HANDLE *Threads;

int	NO_PROCESSORS;
int sti = INITIAL_STI;
bool threaded;

DWORD WINAPI AlphaBetaThreadStarter(LPVOID params)
{
	ThreadParams* p;

	while((p = RemoveFromQueue(&operationQueue)) != NULL)
	{
		mainMoveList.moves[p->i].score=-alphabeta(-p->beta,-p->alpha,p->m,mainboard,p->depth-1,1,p->drawTable);
		AddToQueue(&resultQueue, p);
	}

	return 0;
}

void InitThreads(int threadCount, Queue *operationQueue, Queue *resultQueue)
{
	int i;

	Threads = malloc(sizeof(HANDLE)*threadCount);

	for(i=0;i<threadCount;i++)
		Threads[i] = CreateThread(NULL, 0, AlphaBetaThreadStarter, NULL, 0, NULL);
}

void ReleaseThreads(int threadCount)
{
	int i;
	for(i=0;i<threadCount;i++)
		CloseHandle(Threads[i]);

	free(Threads);
}

void InitQueue(Queue *queue, int capacity)
{
	queue->capacity=capacity;
	queue->back = queue->front = queue->data = malloc(sizeof(ThreadParams*)*capacity);
	queue->size=0;
	queue->queueGuardMutex = CreateMutex(NULL, FALSE, NULL);
	queue->queueReadSemaphore = CreateSemaphore(NULL, 0, capacity, NULL);
	queue->queueWriteSemaphore = CreateSemaphore(NULL, capacity, capacity, NULL);
}

void FreeQueue(Queue *queue)
{
	CloseHandle(queue->queueGuardMutex);
	CloseHandle(queue->queueReadSemaphore);
	CloseHandle(queue->queueWriteSemaphore);
	free(queue->data);
}

ThreadParams* RemoveFromQueue(Queue *queue)
{
	ThreadParams* result;
	if(WaitForSingleObject(queue->queueReadSemaphore, INFINITE) == WAIT_OBJECT_0)
	{
		if(WaitForSingleObject(queue->queueGuardMutex, INFINITE) != WAIT_OBJECT_0)
			return NULL;
				
		result = *(queue->front);
		queue->front++;
		if(queue->front-queue->data>=queue->capacity)
			queue->front=queue->data;
		
		queue->size--;
			
		ReleaseSemaphore(queue->queueWriteSemaphore, 1, NULL);
		ReleaseMutex(queue->queueGuardMutex);

		return result;	
	}

	return NULL;
}

void AddToQueue(Queue *queue, ThreadParams* threadParams)
{
	if(WaitForSingleObject(queue->queueWriteSemaphore, INFINITE) != WAIT_OBJECT_0)
		return;

	if(WaitForSingleObject(queue->queueGuardMutex, INFINITE) != WAIT_OBJECT_0)
		return;

	*(queue->back) = threadParams;
	queue->back++;
	if(queue->back-queue->data>=queue->capacity)
		queue->back=queue->data;
	queue->size++;

	ReleaseSemaphore(queue->queueReadSemaphore, 1, NULL);
	ReleaseMutex(queue->queueGuardMutex);
}
